上一章我们介绍了坐标系,了解了如何把经过比例尺映射后的位置属性,转换成可以绘制到画布上的点。那么接下来我们就来看看如何把转换之后的数据真正地画到画布上。

和前面一样,我们首先会从几何图形的相关理论讲起,然后在 Sparrow 中实现相关的部分。那么接下来废话不多说,就让我们开始吧。
# 几何图形理论
几何图形理论主要会介绍两个部分:几何图形(Geometry)和通道(Channel)。了解它们会对我们在选择视觉编码的时候会有帮助,就算再复杂的视觉编码也能被拆分成这两个部分去分析。
在可视化中,几何图形是根据数据集中的实体(Item)或者链接(Link)去绘制的图形元素,它还有一个同义词是标志(Mark)。通道又或者说视觉通道是用来控制几何图形的外观的。
下面是《Visualization Analysis & Design》中的一个例子。(a)条形图中用条这个几何图形来编码两个属性,其中分类属性用条的水平位置通道编码,数值属性用条的竖直位置通道来编码。(b)散点图中用点这个几何图形来编码两个数值属性,它们分别用点的水平和竖直位置通道来编码。©用颜色通道来编码一个额外的分类属性。(d)用大小通道来编码一个额外的数值属性。

不同的几何图形拥有不同的通道和外观,接下来我们会实现以下的几何图形。每个几何图形的特征和可以绘制的图表我们会在实现过程中介绍。

下图中展示了一些常见的视觉通道,它们主要分为两类。数值通道(Magnitude Channel)会我们提供和有多少相关的信息,主要用来编码数值属性,比如下图中的位置(Position)、大小(Size)和倾斜角度(Tilt)都是数值属性;特征通道(Identity Channel)给我们提供是什么、在哪里相关的信息,主要用来编码分类属性,比如下图中的形状(Shape)和颜色(Color)。

在设计可视化的时候的一个难点就是:面对手中的数据,选择什么几何图形的什么通道去编码数据的属性,可以让可视化结果能更加高效地传递信息?这部分的内容我们会在后面的分析篇中涉及,接下来的主要内容是实现几何图形。
在代码中的几何图形和比例尺、坐标一样,都是一个函数,它会将处理好的数据转化成屏幕上的像素点,因为我们的渲染器是基于 SVG 的,所以其实是转换成对应的 SVG 元素。
需要注意的是:几何图形渲染的数据不是一个数组,而是一个对象。这个对象的每一个 key 都是该几何图形的一个通道,对应的 value 是一个数组,数组的每一个元素是数据和该通道绑定的属性的值。具体可以参考以下的例子。
const data = [
{ x: 0.2, y: 0.3, color: 'red' },
{ x: 0.4, y: 0.8, color: 'yellow' },
{ x: 0.1, y: 0.6, color: 'blue' },
]
const values = {
x: [0.2, 0.4, 0.1],
y: [0.3, 0.8, 0.6],
color: ['red', 'yellow', 'blue']
}
所有的几何图形都有如下的函数签名,同时也支持返回该几何图形拥有的通道。这些通道一方面可以对我们渲染的数据进行校验,另一方面可以在后面的开发中使用。
/**
* @param {Renderer} renderer 渲染引擎
* @param {number []} I 索引数组
* @param {[key:string] Scale} scales 每个通道用到的 scale
* @param {[key:string]: number[]} values 每个通道需要渲染的值
* @param {[key: string]: string} directStyles 图形的和通道无关的样式
* @param {Coordinate} coordinate 使用的坐标系
* @returns 渲染的 SVG 元素
*/
function geometry(renderer, I, scales, values, directStyles, coordinate) {}
geometry.channels = () => ({
